-------------------------------------------------------------------------------------
-- -*- coding: utf-8 -*-
--
-- @author:   zxf
-- @email:    07291@qq.com
-- @date:     2024/9/11
-- @module:   team
-- @describe:
-- @version:  v1.0
--

-------------------------------------------------------------------------------------

---@class team
local team = {}
local this = team

local import = import
local main_ctx = main_ctx
---@type api
local api = import('api/api')
local json = import('bt/bt_plugin/json')
---@type team_cfg
local team_cfg = import('game/config/team_cfg')
local TEAM_CMD_TYPE = team_cfg.CMD_TYPE

local teamDataType = '成员'
local leadDataType = '队长'
local MAX_TEAM_NUM = 100

-- 判断与保存的数据相比是否是同一个队伍
function this.is_same_team_by_saveData(owner, isNotCheckLeader)
    local teamData, leaderData = this.read_teamData_from_server(owner)
    local teamList = api.get_team_member_list()
    if not teamList or #teamList <= 0 then
        xxmsg('没有队伍，等待组队中...')
        return false
    end
    if not teamData or not leaderData then
        return false
    end
    local curIndex, firstIndex, lastIndex, leaderIndex = this.get_my_teamData_index(owner, teamData)
    local dataLeader = leaderData[leaderIndex]
    local isSame = true
    -- 实际队伍数据
    for _, v in ipairs(teamList) do
        isSame = false
        -- 存储的队伍数据
        for i = firstIndex, lastIndex do
            local tmpTeamData = teamData[i]
            if tmpTeamData and not tmpTeamData.isDelete and v.id == tmpTeamData.id then
                -- 队长判断
                if not isNotCheckLeader then
                    if v.is_leader then
                        if dataLeader == v.name then
                            isSame = true
                        else
                            xxmsg('队长数据和游戏中不一致')
                        end
                    else
                        isSame = true
                    end
                else
                    isSame = true
                end
            end
            if isSame then
                break
            end
        end
        if not isSame then
            break
        end
    end
    if not dataLeader then
        isSame = false
    end
    return isSame, teamList
end

-- 判断是否完成队伍
function this.is_finish_team(owner, isNotCheckLeader)
    local isSame, teamList = this.is_same_team_by_saveData(owner, isNotCheckLeader)
    if isSame then
        if teamList and #teamList == owner.need_team_num then
            return true
        end
    end
    return false
end

-- 得到角色在队伍中的索引
function this.get_my_teamData_index(owner, teamData)
    local MAX_MEMBER_COUNT = owner.need_team_num
    local curIndex, firstIndex, lastIndex, leaderIndex = 0, 0, 0, 0
    for i, tmpTeam in ipairs(teamData) do
        if tmpTeam and not tmpTeam.isDelete and tmpTeam.name == owner.name then
            curIndex = i
            break
        end
    end
    leaderIndex = math.ceil(curIndex / MAX_MEMBER_COUNT)
    firstIndex = (leaderIndex - 1) * MAX_MEMBER_COUNT + 1
    lastIndex = firstIndex + MAX_MEMBER_COUNT - 1
    return curIndex, firstIndex, lastIndex, leaderIndex
end

-- 得到角色在队伍中的数据
function this.get_myData_in_teamData(owner, teamData)
    if not teamData then
        return nil
    end
    local curIndex, firstIndex, lastIndex, leaderIndex = this.get_my_teamData_index(owner, teamData)
    return teamData[curIndex]
end

-------------------------------------------------------
-------------------------server------------------------

function this.get_redisPath()
    local regionName = main_ctx:c_region_name()
    local serverName = main_ctx:c_server_name()
    local path = "夜鸦:队伍数据共享"
    return string.format("%s:%s:%s", path, regionName, serverName)
end

function this.get_leaderData_redisPath(owner)
    local sectionType = owner.need_team_num
    local teamUpTargetData = owner.teamUpTargetData or ""
    return string.format("%s:%s:%s人队:%s", this.get_redisPath(), teamUpTargetData,
        sectionType, leadDataType)
end

function this.get_teamData_redisPath(owner)
    local sectionType = owner.need_team_num
    local teamUpTargetData = owner.teamUpTargetData or ""
    return string.format("%s:%s:%s人队:%s", this.get_redisPath(), teamUpTargetData,
        sectionType, teamDataType)
end

-- 读取队伍数据
function this.read_teamData_from_server(owner)
    return this.read_teamData_from_redis(owner)
end

-- 更新队伍数据
function this.update_teamData_to_server(owner, leaderData, teamData)
    this.update_teamData_to_redis(owner, leaderData, teamData)
end

-- 更新个人数据
function this.update_ownerData_to_server(owner, leaderData, teamData)
    local teamPath = this.get_teamData_redisPath(owner)
    local leadPath = this.get_leaderData_redisPath(owner)
    if teamData then
        local curIndex, firstIndex, lastIndex, leaderIndex = this.get_my_teamData_index(owner, teamData)
        local myData = teamData[curIndex]
        main_ctx:redis_set_string(teamPath .. curIndex, json.encode(myData))
    end
    if leaderData then
        main_ctx:redis_set_string(leadPath, json.encode(leaderData))
    end
end

-- 更新队伍数据到redis
function this.update_teamData_to_redis(owner, leaderData, teamData)
    local teamPath = this.get_teamData_redisPath(owner)
    local leadPath = this.get_leaderData_redisPath(owner)
    if teamData then
        local curIndex, firstIndex, lastIndex, leaderIndex = this.get_my_teamData_index(owner, teamData)
        local myData = teamData[curIndex]
        for i = firstIndex, lastIndex do
            local tmpData = teamData[i]
            if tmpData then
                main_ctx:redis_set_string(teamPath .. i, json.encode(myData))
            end
        end
    end
    if leaderData then
        main_ctx:redis_set_string(leadPath, json.encode(leaderData))
    end
end

-- 读取
function this.read_teamData_from_redis(owner)
    local teamData = {}
    local leaderData = nil
    local leadPath = this.get_leaderData_redisPath(owner)
    local teamPath = this.get_teamData_redisPath(owner)
    for i = 1, MAX_TEAM_NUM do
        local teamDataStr = main_ctx:redis_get_string(teamPath .. i)
        if teamDataStr and teamDataStr ~= '' then
            teamData[i] = json.decode(teamDataStr)
        else
            teamData[i] = nil
        end
    end
    local leaderDataStr = main_ctx:redis_get_string(leadPath)
    if leaderDataStr and leaderDataStr ~= '' then
        leaderData = json.decode(leaderDataStr)
    end
    return teamData, leaderData
end

-- 更新或创建角色数据
function this.copy_or_create_role_data(owner, ret)
    if not ret then
        ret = {}
    end
    ret.id = owner.id
    ret.name = owner.name
    ret.curMainTarget = owner:get_curMainTarget()
    ret.level = owner.level
    ret.time = tostring(os.time())
    ret.isDelete = false
    if not ret.pos then
        ret.pos = {}
    end
    ret.pos.x = math.floor(owner.pos.x)
    ret.pos.y = math.floor(owner.pos.y)
    ret.pos.z = math.floor(owner.pos.z)
    ret.mapId = tostring(owner.map_id)
    ret.hp = owner.hp
    ret.max_hp = owner.max_hp
    return ret
end

-- 刷新队伍数据
function this.update_teamData(owner, deltaTime)
    local teamData, leaderData = this.read_teamData_from_server(owner)
    deltaTime = deltaTime or 10
    local time = os.time()
    if not teamData[1] then
        teamData = {}
        leaderData = {}
        table.insert(teamData, this.copy_or_create_role_data(owner))
    else
        local isUpdate = false
        if leaderData then
            for i = 1, #leaderData do
                local leaderLast = leaderData[i]
                for j = i + 1, #leaderData do
                    local leaderNext = leaderData[j]
                    if leaderLast == leaderNext then
                        xxmsg(string.format('移除重复队长 【%s】 【%s】', j, leaderNext))
                        table.remove(leaderData, j)
                        break
                    end
                end
            end
        end

        for i, v in ipairs(teamData) do
            if v then
                if v then
                    local tmpTime = tonumber(v.time)
                    if time - tmpTime > deltaTime then
                        if not v.isDelete and leaderData then
                            for tmpIndex, name in ipairs(leaderData) do
                                if name == v.name then
                                    xxmsg('移除超时队长', v.name)
                                    table.remove(leaderData, tmpIndex)
                                    break
                                end
                            end
                        end
                        v.isDelete = true
                    end
                    if not isUpdate and not v.isDelete and v.name == owner.name then
                        isUpdate = true
                        this.copy_or_create_role_data(owner, v)
                    end
                end
            end
        end
        if not isUpdate then
            local insertIndex = -1
            for i, v in ipairs(teamData) do
                if not v or v.isDelete then
                    insertIndex = i
                    break
                end
            end
            if insertIndex ~= -1 then
                teamData[insertIndex] = this.copy_or_create_role_data(owner)
            end
        end
    end
    this.update_ownerData_to_server(owner, leaderData, teamData)
end

-- 编码命令数据
function this.encode_cmdData(cmdType, cmdData)
    return cmdType, cmdData
end

-- 解码命令数据
function this.decode_cmdData(cmdType, cmdData)
    return cmdType, cmdData
end

-------------------------server------------------------
-------------------------------------------------------

-- 自己在数据中是否是队长
function this.is_leader_in_leaderData(owner)
    local teamData, leaderData = this.read_teamData_from_server(owner)
    return this.is_in_leaderData(owner, leaderData)
end

function this.is_in_leaderData(owner, leaderData)
    if leaderData then
        for _, v in ipairs(leaderData) do
            if v == owner.name then
                return true
            end
        end
    end
    return false
end

-- 邀请提示是否为队长发出
function this.is_leader_invite_msg(owner, msgName)
    local MAX_MEMBER_COUNT = owner.need_team_num
    local teamData, leaderData = this.read_teamData_from_server(owner)
    local curIndex, firstIndex, lastIndex, leaderIndex = this.get_my_teamData_index(owner, teamData, MAX_MEMBER_COUNT)
    if leaderData[leaderIndex] == msgName then
        return true
    end
    return false
end

-- 获取队伍攻击的怪物
function this.get_team_need_attack_monster(owner, actorArr, teamData, cfgArr)
    local tmpTeamData = teamData
    local tmpLeaderData = nil
    local tmpActorArr = actorArr
    if not tmpActorArr then
        tmpActorArr = actor_unit.list(2)
    end
    if not tmpTeamData then
        tmpTeamData, tmpLeaderData = this.read_teamData_from_server(owner)
    end
    if not tmpTeamData then
        return nil
    end
    local curIndex, firstIndex, lastIndex, leaderIndex = this.get_my_teamData_index(owner, tmpTeamData)
    local selectMonster = nil
    local monsterArr = {}
    for i = firstIndex, lastIndex do
        local memberData = tmpTeamData[i]
        if memberData and not memberData.isDelete then
            if memberData.attack_monster_id then
                for _, actor in ipairs(tmpActorArr) do
                    if actor.id == memberData.attack_monster_id then
                        table.insert(monsterArr, actor)
                    end
                end
            end
        end
    end

    if cfgArr then
        for _, cfg in ipairs(cfgArr) do
            for _, v in ipairs(monsterArr) do
                if v.name == cfg.name then
                    local pos = { x = v.cx, y = v.cy, z = v.cz }
                    local dis = common.get_dis_by_pos(owner.pos, pos)
                    if dis < 1500 then
                        selectMonster = v
                        break
                    end
                end
            end
            if selectMonster then
                break
            end
        end
    else
        for _, v in ipairs(monsterArr) do
            local pos = { x = v.cx, y = v.cy, z = v.cz }
            local dis = common.get_dis_by_pos(owner.pos, pos)
            if dis < 1500 then
                if not selectMonster or selectMonster.hp > v.hp then
                    selectMonster = v
                end
            end
        end
    end
    return selectMonster
end

return this
